/******************************************************************************* * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.ui.refactoring; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.Text; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.layout.PixelConverter; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.Document; import org.eclipse.ui.PlatformUI; import org.eclipse.ltk.core.refactoring.Refactoring; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.ui.refactoring.RefactoringWizard; import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.internal.corext.refactoring.ParameterInfo; import org.eclipse.jdt.internal.corext.refactoring.StubTypeContext; import org.eclipse.jdt.internal.corext.refactoring.structure.ChangeSignatureProcessor; import org.eclipse.jdt.internal.corext.util.JdtFlags; import org.eclipse.jdt.ui.PreferenceConstants; import org.eclipse.jdt.ui.text.JavaSourceViewerConfiguration; import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; import org.eclipse.jdt.internal.ui.JavaPlugin; import org.eclipse.jdt.internal.ui.dialogs.TextFieldNavigationHandler; import org.eclipse.jdt.internal.ui.javaeditor.JavaSourceViewer; import org.eclipse.jdt.internal.ui.refactoring.contentassist.ControlContentAssistHelper; import org.eclipse.jdt.internal.ui.refactoring.contentassist.JavaTypeCompletionProcessor; import org.eclipse.jdt.internal.ui.util.ExceptionHandler; public class ChangeSignatureWizard extends RefactoringWizard { private final ChangeSignatureProcessor fProcessor; public ChangeSignatureWizard(ChangeSignatureProcessor processor, Refactoring refactoring) { super(refactoring, DIALOG_BASED_USER_INTERFACE); fProcessor= processor; setDefaultPageTitle(RefactoringMessages.ChangeSignatureRefactoring_modify_Parameters); } @Override protected void addUserInputPages(){ addPage(new ChangeSignatureInputPage(fProcessor)); } private static class ChangeSignatureInputPage extends UserInputWizardPage { public static final String PAGE_NAME= "ChangeSignatureInputPage"; //$NON-NLS-1$ private JavaSourceViewer fSignaturePreview; private Document fSignaturePreviewDocument; private Button fLeaveDelegateCheckBox; private Button fDeprecateDelegateCheckBox; private final ChangeSignatureProcessor fProcessor; public ChangeSignatureInputPage(ChangeSignatureProcessor processor) { super(PAGE_NAME); fProcessor= processor; setMessage(RefactoringMessages.ChangeSignatureInputPage_change); fSignaturePreviewDocument= new Document(); } /* * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) */ public void createControl(Composite parent) { Composite composite= new Composite(parent, SWT.NONE); final GridLayout layout= new GridLayout(); composite.setLayout(layout); initializeDialogUnits(composite); try { createHeadControls(composite); createParameterExceptionsFolder(composite); fLeaveDelegateCheckBox= DelegateUIHelper.generateLeaveDelegateCheckbox(composite, getRefactoring(), false); if (fLeaveDelegateCheckBox != null) { fDeprecateDelegateCheckBox= new Button(composite, SWT.CHECK); GridData data= new GridData(); data.horizontalAlignment= GridData.FILL; data.horizontalIndent= (layout.marginWidth + fDeprecateDelegateCheckBox.computeSize(SWT.DEFAULT, SWT.DEFAULT).x); data.horizontalSpan= 2; fDeprecateDelegateCheckBox.setLayoutData(data); fDeprecateDelegateCheckBox.setText(DelegateUIHelper.getDeprecateDelegateCheckBoxTitle()); final ChangeSignatureProcessor processor= getChangeMethodSignatureProcessor(); fDeprecateDelegateCheckBox.setSelection(DelegateUIHelper.loadDeprecateDelegateSetting(processor)); processor.setDeprecateDelegates(fDeprecateDelegateCheckBox.getSelection()); fDeprecateDelegateCheckBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { processor.setDeprecateDelegates(fDeprecateDelegateCheckBox.getSelection()); } }); fDeprecateDelegateCheckBox.setEnabled(fLeaveDelegateCheckBox.getSelection()); fLeaveDelegateCheckBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { fDeprecateDelegateCheckBox.setEnabled(fLeaveDelegateCheckBox.getSelection()); } }); } Label sep= new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL); sep.setLayoutData((new GridData(GridData.FILL_HORIZONTAL))); createSignaturePreview(composite); update(false); setControl(composite); Dialog.applyDialogFont(composite); } catch (JavaModelException e) { ExceptionHandler.handle(e, RefactoringMessages.ChangeSignatureInputPage_Change_Signature, RefactoringMessages.ChangeSignatureInputPage_Internal_Error); } PlatformUI.getWorkbench().getHelpSystem().setHelp(composite, IJavaHelpContextIds.MODIFY_PARAMETERS_WIZARD_PAGE); } private void createHeadControls(Composite parent) throws JavaModelException { //must create controls column-wise to get mnemonics working: Composite composite= new Composite(parent, SWT.NONE); composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); GridLayout layout= new GridLayout(3, false); layout.marginHeight= 0; layout.marginWidth= 0; composite.setLayout(layout); createAccessControl(composite); createReturnTypeControl(composite); createNameControl(composite); } private void createAccessControl(Composite parent) throws JavaModelException { Composite access= new Composite(parent, SWT.NONE); GridLayout layout= new GridLayout(); layout.marginHeight= 0; layout.marginWidth= 0; access.setLayout(layout); final int[] availableVisibilities= getChangeMethodSignatureProcessor().getAvailableVisibilities(); int currentVisibility= getChangeMethodSignatureProcessor().getVisibility(); Label label= new Label(access, SWT.NONE); label.setText(RefactoringMessages.ChangeSignatureInputPage_access_modifier); final Combo combo= new Combo(access, SWT.DROP_DOWN | SWT.READ_ONLY); if (availableVisibilities.length == 0) { combo.setEnabled(false); } else { for (int i= 0; i < availableVisibilities.length; i++) { combo.add(getAccessModifierString(availableVisibilities[i])); } combo.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { int newVisibility= availableVisibilities[combo.getSelectionIndex()]; getChangeMethodSignatureProcessor().setVisibility(newVisibility); update(true); } }); } combo.setText(getAccessModifierString(currentVisibility)); combo.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); // ensure that "Access modifier:" and "Return type:" Labels are not too close: Dialog.applyDialogFont(access); access.pack(); int minLabelWidth= label.getSize().x + 3 * layout.horizontalSpacing; if (minLabelWidth > combo.getSize().x) label.setLayoutData(new GridData(minLabelWidth, label.getSize().y)); } private String getAccessModifierString(int modifier) { switch (modifier) { case Modifier.PUBLIC : return JdtFlags.VISIBILITY_STRING_PUBLIC; case Modifier.PROTECTED : return JdtFlags.VISIBILITY_STRING_PROTECTED; case Modifier.NONE : return RefactoringMessages.ChangeSignatureInputPage_default; case Modifier.PRIVATE : return JdtFlags.VISIBILITY_STRING_PRIVATE; default : throw new IllegalArgumentException("\"" + modifier + "\" is not a Modifier constant"); //$NON-NLS-1$ //$NON-NLS-2$ } } private void createReturnTypeControl(Composite parent) { Composite returnType= new Composite(parent, SWT.NONE); returnType.setLayoutData(new GridData(GridData.FILL_BOTH)); GridLayout layout= new GridLayout(1, false); layout.marginHeight= 0; layout.marginWidth= 0; returnType.setLayout(layout); Label label= new Label(returnType, SWT.NONE); label.setText(RefactoringMessages.ChangeSignatureInputPage_return_type); final Text text= new Text(returnType, SWT.BORDER); text.setText(getChangeMethodSignatureProcessor().getReturnTypeString()); text.setLayoutData((new GridData(GridData.FILL_HORIZONTAL))); TextFieldNavigationHandler.install(text); if (getChangeMethodSignatureProcessor().canChangeNameAndReturnType()) { text.addModifyListener(new ModifyListener(){ public void modifyText(ModifyEvent e) { getChangeMethodSignatureProcessor().setNewReturnTypeName(text.getText()); update(true); } }); } else { text.setEnabled(false); } JavaTypeCompletionProcessor processor= new JavaTypeCompletionProcessor(true, true); StubTypeContext stubTypeContext= getChangeMethodSignatureProcessor().getStubTypeContext(); processor.setCompletionContext(stubTypeContext.getCuHandle(), stubTypeContext.getBeforeString(), stubTypeContext.getAfterString()); ControlContentAssistHelper.createTextContentAssistant(text, processor); } private void createNameControl(Composite parent) { Composite name= new Composite(parent, SWT.NONE); name.setLayoutData(new GridData(GridData.FILL_BOTH)); GridLayout layout= new GridLayout(1, false); layout.marginHeight= 0; layout.marginWidth= 0; name.setLayout(layout); Label label= new Label(name, SWT.NONE); label.setText(RefactoringMessages.ChangeSignatureInputPage_method_name); final Text text= new Text(name, SWT.BORDER); text.setText(getChangeMethodSignatureProcessor().getMethodName()); text.setLayoutData((new GridData(GridData.FILL_HORIZONTAL))); TextFieldNavigationHandler.install(text); if (getChangeMethodSignatureProcessor().canChangeNameAndReturnType()) { text.addModifyListener(new ModifyListener(){ public void modifyText(ModifyEvent e) { getChangeMethodSignatureProcessor().setNewMethodName(text.getText()); update(true); } }); } else { text.setEnabled(false); } } private void createParameterExceptionsFolder(Composite composite) { TabFolder folder= new TabFolder(composite, SWT.TOP); folder.setLayoutData(new GridData(GridData.FILL_BOTH)); TabItem item= new TabItem(folder, SWT.NONE); item.setText(RefactoringMessages.ChangeSignatureInputPage_parameters); item.setControl(createParameterTableControl(folder)); TabItem itemEx= new TabItem(folder, SWT.NONE); itemEx.setText(RefactoringMessages.ChangeSignatureInputPage_exceptions); itemEx.setControl(createExceptionsTableControl(folder)); folder.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { ((TabItem) e.item).getControl().setFocus(); } }); } private Control createParameterTableControl(Composite composite) { Composite border= new Composite(composite, SWT.NONE); border.setLayout(new GridLayout()); String labelText= null; //no label ChangeParametersControl cp= new ChangeParametersControl(border, SWT.NONE, labelText, new IParameterListChangeListener() { public void parameterChanged(ParameterInfo parameter) { update(true); } public void parameterListChanged() { update(true); } public void parameterAdded(ParameterInfo parameter) { update(true); } }, ChangeParametersControl.Mode.CHANGE_METHOD_SIGNATURE, getChangeMethodSignatureProcessor().getStubTypeContext()); cp.setLayoutData(new GridData(GridData.FILL_BOTH)); cp.setInput(getChangeMethodSignatureProcessor().getParameterInfos()); return border; } private Control createExceptionsTableControl(Composite parent) { Composite border= new Composite(parent, SWT.NONE); border.setLayout(new GridLayout()); ChangeExceptionsControl cp= new ChangeExceptionsControl(border, SWT.NONE, new IExceptionListChangeListener() { public void exceptionListChanged() { update(true); } }, getChangeMethodSignatureProcessor().getMethod().getJavaProject()); cp.setLayoutData(new GridData(GridData.FILL_BOTH)); cp.setInput(getChangeMethodSignatureProcessor().getExceptionInfos()); return border; } @Override public void dispose() { DelegateUIHelper.saveLeaveDelegateSetting(fLeaveDelegateCheckBox); DelegateUIHelper.saveDeprecateDelegateSetting(fDeprecateDelegateCheckBox); super.dispose(); } private void createSignaturePreview(Composite composite) { Label previewLabel= new Label(composite, SWT.NONE); previewLabel.setText(RefactoringMessages.ChangeSignatureInputPage_method_Signature_Preview); // //XXX: use ViewForm to draw a flat border. Beware of common problems with wrapping layouts // //inside GridLayout. GridData must be constrained to force wrapping. See bug 9866 et al. // ViewForm border= new ViewForm(composite, SWT.BORDER | SWT.FLAT); IPreferenceStore store= JavaPlugin.getDefault().getCombinedPreferenceStore(); fSignaturePreview= new JavaSourceViewer(composite, null, null, false, SWT.READ_ONLY | SWT.V_SCROLL | SWT.WRAP /*| SWT.BORDER*/, store); fSignaturePreview.configure(new JavaSourceViewerConfiguration(JavaPlugin.getDefault().getJavaTextTools().getColorManager(), store, null, null)); fSignaturePreview.getTextWidget().setFont(JFaceResources.getFont(PreferenceConstants.EDITOR_TEXT_FONT)); fSignaturePreview.adaptBackgroundColor(composite); fSignaturePreview.setDocument(fSignaturePreviewDocument); fSignaturePreview.setEditable(false); //Layouting problems with wrapped text: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=9866 Control signaturePreviewControl= fSignaturePreview.getControl(); PixelConverter pixelConverter= new PixelConverter(signaturePreviewControl); GridData gdata= new GridData(GridData.FILL_BOTH); gdata.widthHint= pixelConverter.convertWidthInCharsToPixels(50); gdata.heightHint= pixelConverter.convertHeightInCharsToPixels(2); signaturePreviewControl.setLayoutData(gdata); // //XXX must force JavaSourceViewer text widget to wrap: // border.setContent(signaturePreviewControl); // GridData borderData= new GridData(GridData.FILL_BOTH); // borderData.widthHint= gdata.widthHint; // borderData.heightHint= gdata.heightHint; // border.setLayoutData(borderData); } private ChangeSignatureProcessor getChangeMethodSignatureProcessor() { return fProcessor; } private void update(boolean displayErrorMessage){ updateStatus(displayErrorMessage); updateSignaturePreview(); } private void updateStatus(boolean displayErrorMessage) { try{ if (getChangeMethodSignatureProcessor().isSignatureSameAsInitial()) { if (displayErrorMessage) setErrorMessage(RefactoringMessages.ChangeSignatureInputPage_unchanged); else setErrorMessage(null); setPageComplete(false); return; } RefactoringStatus nameCheck= getChangeMethodSignatureProcessor().checkSignature(); if (displayErrorMessage) { setPageComplete(nameCheck); } else { setErrorMessage(null); setPageComplete(true); } } catch (JavaModelException e){ setErrorMessage(RefactoringMessages.ChangeSignatureInputPage_Internal_Error); setPageComplete(false); JavaPlugin.log(e); } } private void updateSignaturePreview() { try{ int top= fSignaturePreview.getTextWidget().getTopPixel(); fSignaturePreviewDocument.set(getChangeMethodSignatureProcessor().getNewMethodSignature()); fSignaturePreview.getTextWidget().setTopPixel(top); } catch (JavaModelException e){ ExceptionHandler.handle(e, RefactoringMessages.ChangeSignatureRefactoring_modify_Parameters, RefactoringMessages.ChangeSignatureInputPage_exception); } } } }